/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#include "ARXConfigurator.h"
#include "ui_ARXConfigurator.h"

#include <QMessageBox>
#include <QListWidgetItem>

#include <string>

#include "Utils.h"

using namespace RafMat;
using namespace RafMat::SimInterface;
using namespace std;

ARXConfigurator::ARXConfigurator(QWidget *parent) :
    QGroupBox(parent),
    ui(new Ui::ARXConfigurator)
{
    ui->setupUi(this);
}

ARXConfigurator::~ARXConfigurator()
{
    delete ui;
}

void ARXConfigurator::attachARXObject(IDiscreteObjectSPtr arxObject)
{
    m_arxObject = arxObject;

    vector<IConfigurableSPtr> params = m_arxObject->getParameters();
    updateARXList(params);
}

void ARXConfigurator::updateARXList(const vector<IConfigurableSPtr>& arxParams)
{
    ui->paramsList->clear();
    vector<IConfigurableSPtr>::const_iterator it;

    for(it = arxParams.begin(); it != arxParams.end(); ++it)
    {
        // Do listy dodaj, by użytkownik ujrzeć mógł!
        insertParametersConfiguration(*it);
    }
}

void ARXConfigurator::insertParametersConfiguration(IConfigurableSPtr conf)
{
    QListWidgetItem* nList = new QListWidgetItem(ui->paramsList);
    QVariant var = QVariant::fromValue(conf);
    nList->setText(QString::fromStdString(conf->getName()));
    nList->setData(Qt::UserRole, var);
}

RafMat::SimInterface::IConfigurableSPtr ARXConfigurator::obtainConfFromListItem(QListWidgetItem *item)
{
    QVariant var = item->data(Qt::UserRole);
    return var.value<IConfigurableSPtr>();
}

void ARXConfigurator::on_btnAdd_clicked()
{
    bool ok;
    unsigned int delay = ui->tfDelay->value();
    int switchTime = ui->tfSwitchTime->value();
    double d = ui->tfD->value();

    vector<double> dA = Utils::convertStrToVector(ui->tfDenominator->text().toStdString(), ok);

    if(!ok)
    {
        QMessageBox::warning(this, "Syntax error", "Incorrect denominator. Proper syntax is: '[a0 a1 ... an]'");
        return;
    }

    vector<double> dB = Utils::convertStrToVector(ui->tfNumerator->text().toStdString(), ok);

    if(!ok)
    {
        QMessageBox::warning(this, "Syntax error", "Incorrect numerator. Proper syntax is: '[b0 b1 ... bn]'");
        return;
    }

    vector<double> dC = Utils::convertStrToVector(ui->sdNumerator->text().toStdString(), ok);

    if(!ok)
    {
        QMessageBox::warning(this, "Syntax error", "Incorrect SD numerator. Proper syntax is: '[b0 b1 ... bn]'");
        return;
    }

    vector<double> dAg = Utils::convertStrToVector(ui->ddDen->text().toStdString(), ok);

    if(!ok)
    {
        QMessageBox::warning(this, "Syntax error", "Incorrect DD den. Proper syntax is: '[ag0 ag1 ... agn]'");
        return;
    }


    IConfigurableSPtr p = m_arxObject->insertParameters(dA, dB,dC,dAg,d ,delay, switchTime);
    p->setName(ui->tfName->text().toStdString());
    insertParametersConfiguration(p);
    m_arxObject->updateParameters();
}

void ARXConfigurator::on_paramsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    // Ominięcie ostrzeżenia kompilatora.
    previous = previous;

    if(current != NULL)
    {
        IConfigurableSPtr conf = obtainConfFromListItem(current);

        try {
            ui->tfNumerator->setText(QString::fromStdString(conf->getParameter("bpoly")));
            ui->tfDenominator->setText(QString::fromStdString(conf->getParameter("apoly")));
            ui->sdNumerator->setText(QString::fromStdString(conf->getParameter("cpoly")));
            ui->ddDen->setText(QString::fromStdString(conf->getParameter("agpoly")));
            ui->tfD->setValue(QString::fromStdString(conf->getParameter("d")).toDouble());
            ui->tfDelay->setValue(QString::fromStdString(conf->getParameter("delay")).toInt());
            ui->tfSwitchTime->setValue(QString::fromStdString(conf->getParameter("switch_time")).toInt());
            ui->tfName->setText(QString::fromStdString(conf->getName()));
        } catch (std::logic_error &e) {
            QMessageBox::warning(this, "Error", e.what());
        }
    }
}

void ARXConfigurator::on_btnRemove_clicked()
{
    QListWidgetItem *current = ui->paramsList->currentItem();

    if(current != NULL)
    {
// Zrezygnowano po tym jak IDiscreteObject nie wysyła parametrów z switch_time = -2
//        if(ui->paramsList->count() == 1)
//        {
//            QMessageBox::warning(this, "You mad brah?", "There must exist at least one transfer function.");
//            return;
//        }

        IConfigurableSPtr conf = obtainConfFromListItem(current);
        m_arxObject->deleteParameters(conf);
        delete current;
    }
}

void ARXConfigurator::on_btnApply_clicked()
{
    QListWidgetItem *current = ui->paramsList->currentItem();

    if(current == NULL)
        return;

//    bool ok;
//    unsigned int delay = ui->tfDelay->value();
//    int switchTime = ui->tfSwitchTime->value();
//    Utils::convertStrToVector(ui->tfNumerator->text().toStdString(), ok);

//    if(!ok)
//    {
//        QMessageBox::warning(this, "Syntax error", "Incorrect numerator. Proper syntax is: '[b0 b1 ... bn]'");
//        return;
//    }

//    Utils::convertStrToVector(ui->tfDenominator->text().toStdString(), ok);

//    if(!ok)
//    {
//        QMessageBox::warning(this, "Syntax error", "Incorrect denominator. Proper syntax is: '[a0 a1 ... an]'");
//        return;
//    }

    IConfigurableSPtr conf = obtainConfFromListItem(current);
    QString txt = ui->tfName->text();
    conf->setName(txt.toStdString());
    current->setText(txt);

    string oldAPoly, oldBPoly, oldDelay, oldSwTime;
    \
    // TODO: bezpieczeństwo transakcyjne
    // np. buforowanie przesyłanych danych
    // updateParameters() mógłby spowodować skopiowanie
    // danych tymczasowych do danych bieżących.

    try
    {
        // Koniecznie najpierw bpoly!
        conf->setParameter("agpoly", ui->ddDen->text().toStdString());
		conf->setParameter("cpoly", ui->sdNumerator->text().toStdString());
        conf->setParameter("bpoly", ui->tfNumerator->text().toStdString());
        conf->setParameter("apoly", ui->tfDenominator->text().toStdString());

        // Dziwna konwersja najpierw do QString dopiero potem do std::string
        // Wszystko dlatego ze QString ma fromInt.
        conf->setParameter("d", QString::number(ui->tfD->value()).toStdString());
        conf->setParameter("delay", QString::number(ui->tfDelay->value()).toStdString());
        conf->setParameter("switch_time", QString::number(ui->tfSwitchTime->value()).toStdString());
        m_arxObject->updateParameters();
    }
    catch(std::logic_error &e)
    {
        QMessageBox::warning(this, "Error", e.what());
    }
}
